package com.company.server;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Data
@NoArgsConstructor
public class ServerThread implements Runnable{
    private Socket client; // 用于接收客户端的 Socket对象
    private DataOutputStream dos; // 用于缓存每个客户端 socket的 DataOutputStream 对象
    public ServerThread(Socket client) {
        this.client = client;
    }
    @Override
    public void run() {
        // 线程执行的逻辑
        try {
            // 使用特殊数据流接收客户端发送过来的数据
            DataInputStream dis = new DataInputStream(client.getInputStream());
            while (true) {
                int type = dis.readInt();
                switch (type){
                    case 1: // 代表客户端发送过来的是 登录请求
                        String username = dis.readUTF();
                        Server.allOnlineUsers.put(client, username); // 将客户端的 Socket对象 和 用户名存入到集合中
                        // 初始化当前客户端的输出流，并缓存到全局集合中
                        dos = new DataOutputStream(client.getOutputStream());
                        Server.allOnlineUsersOutputStream.put(client, dos);
                        System.out.println("客户端：" + client.getInetAddress().getHostAddress() + "，端口号：" + client.getPort() + "，用户名：" + username + "，上线了");
                        broadcastOnlineUsers();
                        break;
                    case 2: // 代表客户端发送过来的是 群聊请求
                        String message = dis.readUTF();
                        handleGroupChat(message);
                        break;
                    case 3: // 代表客户端发送过来的是 私聊请求
                        String privateUserName = dis.readUTF(); // 获取私聊对象的用户名
                        String privateMessage = dis.readUTF(); // 获取私聊消息
                        handlePrivateChat(privateUserName, privateMessage);
                        break;
                }
            }
        } catch (Exception e) {
            System.out.println("客户端："+ client.getInetAddress().getHostAddress() + ":" + client.getPort() + "断开连接！");
            // 当捕获到异常时，表示该客户端断开连接，那么需要从在线用户列表中移除
            Server.allOnlineUsers.remove(client);
            broadcastOnlineUsers();
        }
    }

    /***
     * 处理私聊消息
     * @param privateMessage：私聊消息
     * @param privateUserName：私聊对象的用户名
     */
    private void handlePrivateChat(String privateUserName, String privateMessage) throws Exception {
        Socket targetSocket = null;
        // 查找目标私聊用户的 Socket
        Set<Map.Entry<Socket, String>> allUsersKeyValues = Server.allOnlineUsers.entrySet();
        for (Map.Entry<Socket, String> keyValue : allUsersKeyValues) {
            if (keyValue.getValue().equals(privateUserName)){
                targetSocket = keyValue.getKey(); // 获取目标私聊对象的 Socket管道
                break;
            }
        }
        // 获取当前时间，并自定义格式
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd EEEE HH:mm:ss", Locale.CHINA);
        String dateTime = now.format(formatter);
        // 拼接消息（消息发送者 + 消息发送时间 + 消息）
        StringBuilder sb = new StringBuilder();
        String allPrivateMsg = sb.append(Server.allOnlineUsers.get(client)).append(" ").append(dateTime).append("\r\n").append(privateMessage).append("\r\n").toString();
        // 讲私聊发起方的消息显示在双方的界面上
        DataOutputStream outClient = Server.allOnlineUsersOutputStream.get(client);
        outClient.writeInt(3); // 代表发送的是 私聊消息的请求
        outClient.writeUTF(privateUserName);
        outClient.writeUTF(allPrivateMsg);
        outClient.flush();
        // 给目标用户发送消息时，保持发送者的名字
        DataOutputStream outTarget = Server.allOnlineUsersOutputStream.get(targetSocket);
        outTarget.writeInt(3); // 代表发送的是 私聊消息的请求
        outTarget.writeUTF(Server.allOnlineUsers.get(client));
        outTarget.writeUTF(allPrivateMsg);
        outTarget.flush();
    }

    /**
     * 向所有在线客户端推送更新后的在线用户列表
     */
    private void broadcastOnlineUsers() {
        Collection<String> allUsersNames = new ArrayList<>(); // 存储所有在线用户的用户名
        Set<Socket> allUsers = Server.allOnlineUsers.keySet(); // 获取所有在线用户的 Socket对象
        for (Socket socket : allUsers) {
            allUsersNames.add(Server.allOnlineUsers.get(socket)); // 获取在线用户的用户名，并存储到集合中
        }
        // 遍历所有在线客户端，向每个客户端发送最新的在线用户列表
        for (Socket socket : allUsers){
            try {
                DataOutputStream out = Server.allOnlineUsersOutputStream.get(socket);
                out.writeInt(1); // 代表发送的是 在线用户列表的请求
                int size = allUsersNames.size();
                out.writeInt(size); // 告诉客户端要接收的在线用户数量
                for (String user : allUsersNames){
                    out.writeUTF(user);
                }
                // 刷新输出流，确保数据立即发送给客户端
                out.flush();
            } catch (Exception e) {
                System.out.println("向客户端：" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "发送在线用户列表失败！");
                e.printStackTrace();
            }
        }
    }
    private void handleGroupChat(String message) {
        // 获取当前时间，并自定义格式
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd EEEE HH:mm:ss", Locale.CHINA);
        String dateTime = now.format(formatter);
        // 拼接消息（消息发送者 + 消息发送时间 + 消息）
        StringBuilder sb = new StringBuilder();
        String allMsg = sb.append(Server.allOnlineUsers.get(client)).append(" ").append(dateTime).append("\r\n").append(message).append("\r\n").toString();
        // 遍历所有在线客户端，向每个客户端发送群聊消息
        for (Socket socket : Server.allOnlineUsers.keySet()){
            try {
                DataOutputStream out = Server.allOnlineUsersOutputStream.get(socket);
                out.writeInt(2); // 代表发送的是 群聊消息的请求
                out.writeUTF(allMsg);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
